import pandas as pd
import yfinance as yf
import numpy as np
import plotly.graph_objects as go
import plotly.express as px
import matplotlib.pyplot as plt
data source: Yahoo finance
granularity: 1 day time period
start date: 2017-01-01
end date: 2020-10-05
tickers: BTC-USD, ETH-USD, LTC-USD
tickers = ['BTC-USD','ETH-USD', 'LTC-USD', 'XRP-USD']
#tickers = ['SPY', 'AAPL']
data_1d = yf.download(tickers, start="2017-01-01", end="2020-10-05", group_by="ticker" ,interval = "1d")
for ticker in tickers:
fig = go.Figure(data=[go.Candlestick(x=data_1d.index,
open=data_1d[ticker]['Open'],
high=data_1d[ticker]['High'],
low=data_1d[ticker]['Low'],
close=data_1d[ticker]['Close'])])
fig.update_layout(xaxis_rangeslider_visible=False, title=ticker, xaxis_title='Date',yaxis_title='Price')
fig.show()
data_1d_pct = pd.DataFrame(index=data_1d.index, columns = tickers)
for ticker in tickers:
data_1d_pct[ticker]= data_1d[ticker]['Close'].pct_change().values *100
for ticker in tickers:
plt.figure(figsize=(20,5))
plt.plot(data_1d_pct[ticker], 'b');
plt.xlabel('Date');
plt.ylabel('Daily returns [%]');
plt.title(ticker);
This chart shows returns dependency between BTC-USD and ETH-USD
x = data_1d_pct.iloc[1:,0]
y = data_1d_pct.iloc[1:,1]
plt.figure(figsize=(10,10))
plt.scatter(data_1d_pct.iloc[1:,0], data_1d_pct.iloc[1:,1]);
plt.xlabel(str(data_1d_pct.columns[0]) + str(' returns [%]'));
plt.ylabel(str(data_1d_pct.columns[1]) + str(' returns [%]'));
plt.title('Scatter chart');
This heatmap shows correlation matrix for all downloaded cryptocurrencies
data_1d_pct = pd.DataFrame(index=data_1d.index, columns = tickers)
for ticker in tickers:
data_1d_pct[ticker]= data_1d[ticker]['Close'].pct_change().values *100
data_1d_pct_corr = data_1d_pct.dropna()
data_1d_corr = data_1d_pct_corr.corr()
fig = go.Figure(data=go.Heatmap(
z=data_1d_corr,
x=data_1d_corr.columns,
y=data_1d_corr.index,
colorscale = 'Viridis'))
fig.show()
This chart shows rolling correlation with 30 days period.
data_1d_rollingcorr = pd.DataFrame(index=data_1d.index, columns = tickers)
done = np.array([])
for ticker in tickers:
for tic in tickers:
done = np.append(done, [tic+ticker])
if ticker != tic and (ticker+tic) not in done:
rollcorr = data_1d_pct[tic].rolling(30).corr(data_1d_pct[ticker])
plt.figure(figsize=(20,5))
plt.plot(rollcorr, 'b');
plt.xlabel('Date');
plt.ylabel('Correlation [-]');
plt.title(str(ticker) + str(" x ") + str(tic) + str(" - rolling correlation"));
This chart shows autocorrelation for each cryptocurrency with 1 to 5 day lags.
data_1d_autocorr = pd.DataFrame(index=['Day_1', 'Day_2', 'Day_3', 'Day_4', 'Day_5'], columns = tickers)
for ticker in tickers:
for idx, lag in zip(data_1d_autocorr.index, range(1, len(data_1d_autocorr)+1)):
data_1d_autocorr.xs(idx)[ticker] = data_1d_pct[ticker].autocorr(lag=lag)
fig = go.Figure(data=go.Heatmap(
z=data_1d_autocorr,
x=data_1d_autocorr.columns,
y=data_1d_autocorr.index,
colorscale = 'Viridis'))
fig.show()
data_1d_autocorr
method: Historical
assets: single asset (BTC-USD)
granularily: 1 day time period
initial capital: 100k $
start date: 2017-01-01
end date: 2020-10-05
VAR prediction: 1 day
Confidence: 0.01 - 0.2
ticker=['BTC-USD']
data_1d = yf.download(ticker, start="2017-01-01", end="2020-10-05", group_by="ticker" ,interval = "1d")
data_1d_pct = pd.DataFrame(index=data_1d.index, columns = ticker)
conf_lose = pd.DataFrame(columns = ['confidence','lose'])
initial_capital = 100000
pct_range = np.arange(0.8, 1, 0.01)
days = len(data_1d_pct)
data_1d_pct= data_1d['Close'].pct_change().values
hist_perf = data_1d_pct[1:] * initial_capital
hist_perf_sum_sorted = np.sort(hist_perf)
plt.figure(figsize=(20,5))
plt.plot(hist_perf, 'b');
plt.xlabel('Date');
plt.ylabel('Returns [$]');
plt.title('Portfolio returns');
plt.show()
plt.figure(figsize=(20,5))
plt.plot(hist_perf_sum_sorted, 'b');
plt.xlabel('Date');
plt.ylabel('Returns [$]');
plt.title('Sorted portfolio returns');
plt.show()
plt.figure(figsize=(20,5))
plt.hist(hist_perf_sum_sorted, bins=200);
plt.xlabel('Returns [$]');
plt.ylabel('Count');
plt.title('Returns histogram');
plt.show()
for pct in pct_range:
lose = round(hist_perf_sum_sorted[int(round(days*(1-round(pct,2)), 0))-1],2)
conf_lose = conf_lose.append({'confidence': pct, 'lose' : lose}, ignore_index=True)
print (str('With ') +str(round(pct,2)) +str('% confidence you wan\'t lose more than ')+ str(lose) )
plt.figure(figsize=(20,5))
plt.plot(conf_lose['confidence'], conf_lose['lose'],'bo--', markersize=12)
plt.xlabel('Confidence [%]');
plt.ylabel('Lose [$]');
plt.title('Lose/confidence chart');
plt.show()
method: Historical
assets: portfolio (BTC-USD, ETH-USD, LTC-USD)
portfolio weights: 0.33, 0.33, 0.34
granularily: 1 day time period
initial capital: 100k $
start date: 2019-01-01
end date: 2020-10-05
VAR prediction: 1 day
Confidence: 0.05
Out-of-sample period: 30%
Description: The chart shows value of portfolio(blue line) and Value at Risk(red line) calculated each day with anchored dataset. Value at Risk is simulated on 30% out of sample dataset.
tickers = ['BTC-USD','ETH-USD','LTC-USD']
data_1d = yf.download(tickers, start="2019-01-01", end="2020-10-05", group_by="ticker" ,interval = "1d")
data_1d_pct = pd.DataFrame(index=data_1d.index, columns = tickers)
expected_lose = pd.DataFrame(index=data_1d.index, columns = ['lose', 'lose_price'])
initial_capital = 100000
weights = [0.33, 0.33, 0.34]
out_of_sample = 0.3
pct = 0.95
time_back = int(round(len(data_1d_pct)*out_of_sample,0))
for ticker in tickers:
data_1d_pct[ticker]= data_1d[ticker]['Close'].pct_change().values
for i in range(len(data_1d_pct)-time_back, len(data_1d_pct)-1):
hist_perf = data_1d_pct[1:i] * initial_capital * weights
hist_perf_sum = hist_perf.iloc[:,0] + hist_perf.iloc[:,1] + hist_perf.iloc[:,2]
hist_perf_sum_sorted = hist_perf_sum.sort_values(ascending=True)
lose = round(hist_perf_sum_sorted[int(round(i*(1-pct), 0))-1],2)
expected_lose.iloc[i,0] = lose
expected_lose.iloc[i,1] = hist_perf_sum.cumsum()[-1] + lose + initial_capital
expected_lose['price'] = hist_perf_sum.cumsum() + initial_capital
plt.figure(figsize=(20,10))
plt.plot(expected_lose['price'], 'b');
plt.plot(expected_lose['lose_price'], 'r--');
plt.xlabel('Date');
plt.ylabel('Price');
plt.title('Rolling Vaue at risk');
plt.legend(['Portfolio value','Expected lose']);
method: Bootstrap
assets: portfolio (BTC-USD, ETH-USD)
portfolio weights: 0.5, 0.5
granularily: 1 day time period
start date: 2017-01-01
end date: 2020-10-05
Simulation sample: 50 days
# of simulated portfolios: 50
tickers = ['BTC-USD','ETH-USD']
data_1d = yf.download(tickers, start="2017-01-01", end="2020-10-05", group_by="ticker" ,interval = "1d")
data_1d_pct = pd.DataFrame(index=data_1d.index, columns = tickers)
portfolio_simulations = pd.DataFrame()
portfolio_weight = [0.5, 0.5]
for ticker in tickers:
data_1d_pct[ticker]= data_1d[ticker]['Close'].pct_change().values
data_1d_pct = data_1d_pct.dropna()
for i in range (0, 50):
sim_returns = data_1d_pct.sample(n = 100,replace = True).reset_index(drop = True)
result = sim_returns * portfolio_weight
result = result.sum(axis=1)
portfolio_simulations[str('Portfolio_')+str(i)] = result
portfolio_simulations = portfolio_simulations.cumsum()
last_values = portfolio_simulations.iloc[-1,:]
print(str('\n\nNumber of portfolio simulation with positive performance: ') + str(sum(n > 0 for n in last_values)))
fig = px.line(portfolio_simulations, x=portfolio_simulations.index, y=portfolio_simulations.columns)
fig.update_layout(title="Portfolio simulation", xaxis_title='Day',yaxis_title='Cummulative performance [%]')
fig.show()
method: Bootstrap
assets: portfolio (BTC-USD, ETH-USD)
portfolio weights: 0.5, 0.5
granularily: 1 day time period
start date: 2017-01-01
end date: 2020-10-05
Simulation sample: 50 days
# of simulated portfolios: 50
Scenario: What can happen with portfolio performance, if each profitable day will be 20% lower and each losing day will be 20% bigger.
data_1d_pct = pd.DataFrame(index=data_1d.index, columns = tickers)
portfolio_simulations = pd.DataFrame()
portfolio_weight = [0.5, 0.5]
for ticker in tickers:
data_1d_pct[ticker]= data_1d[ticker]['Close'].pct_change().values
data_1d_pct = data_1d_pct.dropna()
for ticker in tickers:
data_1d_pct.loc[data_1d_pct[ticker] > 0] *= 0.8
data_1d_pct.loc[data_1d_pct[ticker] < 0] *= 1.2
#portfolio simulations
for i in range (0, 50):
sim_returns = data_1d_pct.sample(n = 100,replace = True).reset_index(drop = True)
result = sim_returns * portfolio_weight
result = result.sum(axis=1)
portfolio_simulations[str('Portfolio_')+str(i)] = result
portfolio_simulations = portfolio_simulations.cumsum()
last_values = portfolio_simulations.iloc[-1,:]
print(str('\n\nNumber of portfolio simulation with positive performance: ') + str(sum(n > 0 for n in last_values)))
fig = px.line(portfolio_simulations, x=portfolio_simulations.index, y=portfolio_simulations.columns)
fig.show()
method: Bootstrap
assets: portfolio (BTC-USD, ETH-USD)
portfolio weights: 0.5, 0.5
granularily: 1 day time period
start date: 2017-01-01
end date: 2020-10-05
Simulation sample: 50 days
# of simulated portfolios: 50
Scenario combinations: What can happen with portfolio performance, if each profitable day will be in interval from 50% to 150% of historical value and each losing day will be in interval from 50% to 150% of historical value.
data_1d_pct = pd.DataFrame(index=data_1d.index, columns = tickers)
portfolio_simulations = pd.DataFrame()
portfolio_weight = [0.5, 0.5]
data_1d_pct = data_1d_pct.dropna()
lose_change = np.round(np.arange(0.5, 1.5, 0.01),2)
profit_change = np.round(np.arange(0.5, 1.5, 0.01),2)
from tqdm import tqdm
portfolio_simulation = pd.DataFrame(index = profit_change, columns = lose_change)
for n in tqdm(profit_change):
for m in lose_change:
for ticker in tickers:
data_1d_pct[ticker]= data_1d[ticker]['Close'].pct_change().values
for ticker in tickers:
data_1d_pct.loc[data_1d_pct[ticker] > 0] *= n
data_1d_pct.loc[data_1d_pct[ticker] < 0] *= m
for i in range (0, 50):
sim_returns = data_1d_pct.sample(n = 100,replace = True).reset_index(drop = True)
result = sim_returns * portfolio_weight
result = result.sum(axis=1)
portfolio_simulations[str('Portfolio_')+str(i)] = result
portfolio_simulations = portfolio_simulations.cumsum()
last_values = portfolio_simulations.iloc[-1,:]
portfolio_simulation.xs(n)[m] = float(sum(z > 0 for z in last_values))
fig = go.Figure(data=[go.Surface(z=portfolio_simulation.values, x=portfolio_simulation.index, y=portfolio_simulation.columns)])
fig.update_traces(contours_z=dict(show=True, usecolormap=True,highlightcolor="limegreen", project_z=True))
fig.update_layout(title='Portfolio simulation', autosize=True,
width=800, height=600,
margin=dict(l=0, r=0, b=0, t=30),
scene = dict(
xaxis_title='Negative returns change',
yaxis_title='Positive returns change',
zaxis_title='# of profitable portfolio simulation'))
fig.show()